//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Licensed MIT: http://www.opensource.org/licenses/mit-license.php

using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using DNA.Mvc.Controllers;
using DNA.Mvc.jQuery;
using DNA.OpenAPI.Rss;
using DNA.Mvc.Text;

namespace DNA.Mvc.Community.Controllers
{
    //[Log]
    //[HandleError]
    public partial class ForumController : Controller
    {
        private IForumContext dbContext;

        private ForumWrapper _Wrap(int id)
        {
            var forum = dbContext.Forums.Find(id);
            return new ForumWrapper(forum, dbContext);
        }

        private ForumHierarchicalNodeProvider _CreateForumsProvider()
        {
            return new ForumHierarchicalNodeProvider(dbContext.Forums);
        }

        private ForumGroup _Group(int id)
        {
            var forum = dbContext.Forums.Find(id);
            return new ForumGroup(forum, dbContext);
        }

        public ForumController(IForumContext forumContext)
        {
            dbContext = forumContext;
        }

        [SiteMapAction(Title = "Community")]
        public ActionResult Index()
        {
            var forums = dbContext.Forums.Filter(f => !f.IsGroup && f.ParentID == 0)
                                .OrderBy(f => f.Pos)
                                .ToList()
                                .Select(f => new ForumWrapper(f, this.dbContext));

            var groups = dbContext.Forums.Filter(f => f.IsGroup && f.ParentID == 0)
                .OrderBy(f => f.Pos)
                .ToList()
                .Select(f => new ForumGroup(f, this.dbContext));
            ViewBag.Forums = forums;
            return View(groups);
        }

        public ActionResult Group(int id)
        {
            return View(_Group(id));
        }

        [SecurityAction("Community", "Create forum", "Allows user can create new forum.",
            TitleResName = "SA_CreateForum",
            DescResName = "SA_CreateForumDesc",
            PermssionSetResName = "SA_Community"
            )]
        public ActionResult Create(int id, bool? isgroup)
        {
            ViewData["Parent"] = dbContext.Forums.Find(id);
            ViewData["IsGroup"] = isgroup.HasValue ? isgroup.Value : false;
            return View();
        }

        [SecurityAction("Community", "Create forum", "Allows user can create new forum.",
    TitleResName = "SA_CreateForum",
    DescResName = "SA_CreateForumDesc",
    PermssionSetResName = "SA_Community"
    )]
        [HttpPost, ValidateAntiForgeryToken]
        public ActionResult Create(int id, [Bind(Prefix = "Forum")] Forum forum, FormCollection forms)
        {
            if (ModelState.IsValid)
            {
                forum.ParentID = id;
                var moderators = GetModeratorList(forms);

                if (moderators != null)
                {
                    foreach (var moderator in moderators)
                    {
                        if (!string.IsNullOrEmpty(moderator))
                        {
                            dbContext.Moderators.Create(new Moderator()
                            {
                                Forum = forum,
                                UserName = moderator
                            });
                        }
                    }
                }

                dbContext.Forums.Create(forum);
                var rows = dbContext.SaveChanges();
                return RedirectToAction("Edit", new { id = forum.ID });
            }
            ViewData["IsGroup"] = forum.IsGroup;
            return View(forum);
        }

        [HttpPost]
        [SecurityAction("Community", "Move forum", "Allows user can change the forums relationship",
            TitleResName = "SA_MoveForum",
            DescResName = "SA_MoveForumDesc",
            PermssionSetResName = "SA_Community"
            )]
        public void Move(int id, int parentID, int pos)
        {
            dbContext.Forums.Move(parentID, id, pos);
            dbContext.SaveChanges();
        }

        [HttpPost]
        [SecurityAction("Community", "Delete forum", "Allows user can delete the forum and all data of the forum",
            TitleResName = "SA_DeleteForum",
            DescResName = "SA_DeleteForumDesc",
            PermssionSetResName = "SA_Community"
            )]
        public void Delete(int id)
        {
            dbContext.Forums.Delete(dbContext.Forums.Find(id));
            dbContext.SaveChanges();
        }

        [SiteMapAction(Title = "View threads",
            ShowInMenu = false,
            IsShared = true,
            IgnoreRouteDataKeys = new string[] { "id", "index", "size", "orderby" })]
        [Pagable]
        public ActionResult Threads(int id, QueryParams queryParams)
        {
            Forum forum = dbContext.Forums.Find(id);
            if ((!forum.AllowAnonymous) && (!HttpContext.Request.IsAuthenticated))
                return RedirectToAction("Login", "Account", new { Area = "", returnUrl = (new UrlHelper(ControllerContext.RequestContext).Action("Threads", "Forum", ControllerContext.RouteData.Values)) });

            ViewData["Forum"] = new ForumWrapper(forum, dbContext);

            int total = 0;
            var fields = !string.IsNullOrEmpty(queryParams.OrderBy) ? queryParams.OrderBy.Split('~') : null;
            var sortingField = (fields != null && fields.Count() > 0) ? fields[0] : "";
            var sortOrder = SortingOrders.Asc;

            if (fields != null && fields.Count() > 1)
            {
                if (fields[1].Equals("desc", System.StringComparison.OrdinalIgnoreCase))
                    sortOrder = SortingOrders.Desc;
            }

            var threads = dbContext.Forums.GetThreads(id, sortingField, sortOrder, (queryParams.Index > 0 ? queryParams.Index - 1 : queryParams.Index), queryParams.Size, out total);

            WebSiteContext.Current.Title = forum.Title;

            if (!string.IsNullOrEmpty(forum.Description))
                WebSiteContext.Current.Description = forum.Description;

            return View(new ModelWrapper()
            {
                Model = threads,
                Total = total
            });
        }

        [SecurityAction("Community", "Edit forum", "Allows user can edit the forum settings",
            TitleResName = "SA_EditForum",
            DescResName = "SA_EditForumDesc",
            PermssionSetResName = "SA_Community"
            )]
        public ActionResult Edit(int id)
        {
            var forum = dbContext.Forums.Find(id);
            ViewData.Model = forum;
            ViewData["IsGroup"] = forum.IsGroup;
            return PartialView();
        }

        public ActionResult Welcome()
        {
            ViewData.Model = new ForumStat(this.dbContext);
            return PartialView();
        }

        [SecurityAction("Community", "Edit forum", "Allows user can edit the forum settings",
            TitleResName = "SA_EditForum",
            DescResName = "SA_EditForumDesc",
            PermssionSetResName = "SA_Community"
            ), HttpPost, ValidateAntiForgeryToken]
        public ActionResult Edit(int id, FormCollection form)
        {
            var forum = dbContext.Forums.Find(id);
            var _including = new string[] { "Title", "Description", "IsLocked", "IsModerated", "AllowAttachment", "AllowAnonymous", "ImageUrl" };

            if (forum.IsGroup)
                _including = new string[] { "Title", "Description" };

            if (TryUpdateModel<Forum>(forum, "Forum", _including))
            {
                if (!forum.IsGroup)
                {
                    if (forum.Moderators.Count > 0)
                    {
                        var ms = forum.Moderators.ToList();
                        foreach (var m in ms)
                            dbContext.Moderators.Delete(m);
                        forum.Moderators.Clear();
                        dbContext.Forums.Update(forum);
                        dbContext.SaveChanges();
                    }

                    var moderators = GetModeratorList(form);
                    if (moderators != null)
                    {
                        foreach (var moderator in moderators)
                        {
                            dbContext.Moderators.Create(new Moderator()
                            {
                                Forum = forum,
                                UserName = moderator
                            });
                        }

                        if (moderators.Count() > 0)
                        {
                            dbContext.SaveChanges();
                        }
                    }

                    if (forum.Moderators.Count == 0 && moderators == null)
                    {
                        dbContext.Forums.Update(forum);
                        dbContext.SaveChanges();
                    }
                }
                else
                {
                    dbContext.Forums.Update(forum);
                    dbContext.SaveChanges();
                }
                ViewData.Model = forum;
            }

            return PartialView();
        }

        private static string[] GetModeratorList(FormCollection form)
        {
            var _modString = form["Moderators"];
            var _modList = new List<string>();

            if (!string.IsNullOrEmpty(_modString))
            {
                string[] moderators = _modString.Split(new char[] { ',' });

                foreach (var m in moderators)
                {
                    if (!string.IsNullOrEmpty(m))
                    {
                        var member = Membership.GetUser(m);
                        if (member != null)
                            _modList.Add(m);
                    }
                }
                return _modList.ToArray();
            }
            return null;
        }

        [SecurityAction("Community", "Forum manager", "Allows use can use the forum manager.",
            TitleResName = "SA_ForumManager",
            DescResName = "SA_ForumManagerDesc",
            PermssionSetResName = "SA_Community"
            )]
        [SiteControlPanel(ResBaseName = "forums",
            ResKey = "Forums",
            Order = 1,
            Group = "Community",
            GroupResKey = "Community",
            ShowInTopSiteOnly = true)]
        public ActionResult Settings()
        {
            ViewBag.ForumNodesProvider = _CreateForumsProvider();
            return PartialView();
        }

        [PersonalOnly]
        [MyControlPanel(ResBaseName = "forums", ResKey = "MyModerateForums", Group = "Community", GroupResKey = "Community")]
        public ActionResult MyModeratedForums()
        {
            var forums = dbContext.Forums.GetModeratedForums(User.Identity.Name).ToList().Select(f => new ForumWrapper(f, dbContext));
            return View(forums);
        }

        [OutputCache(Duration = 3600, VaryByParam = "*")]
        public ActionResult Rss(int id)
        {
            var forum = _Wrap(id);
            var threads = forum.Threads.Where(t => !t.IsDeleted && t.IsApproved).OrderByDescending(t => t.Posted);

            var rssBuilder = new RssChannelBuilder(forum.Title, forum.Description, UrlResolver.Resolve(HttpContext) + Url.Action("Threads", "Forum", new { Area = "Community", id = id }));

            if (!string.IsNullOrEmpty(forum.ImageUrl))
            {
                string imageUrl = UrlResolver.Resolve(HttpContext) + Url.Content(forum.ImageUrl);
                rssBuilder.SetImage(imageUrl, 180, 60);
            }

            rssBuilder.AddItems(threads, (thread, items) =>
            {
                var _summary = (thread.LastPost != null && !string.IsNullOrEmpty(thread.LastPost.Body)) ? TextEngine.Text(TextEngine.BBCode(thread.LastPost.Body).ToString()) : "";
                items.SetBase(thread.Title, _summary, UrlResolver.Resolve(HttpContext) + Url.Action("Index", "Thread", new { Area = "Community", id = thread.ID }));
                items.SetAuthor(thread.Author);
                items.SetPublished(thread.Posted);
            });
            //var xml = rssBuilder.GetXml();
            //xml = xml.Replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "<rss version=\"2.0\">");
            var rssdoc = new RssDocument()
            {
                Channel = rssBuilder.GetChannel()
            };

            return Content(DNA.Utility.XmlSerializerUtility.SerializeToXml<RssDocument>(rssdoc), "text/xml");
        }
    }
}
